package com.ifinc.common.protocol.i8583;


import com.ifinc.common.protocol.i8583.field.Field;
import com.ifinc.common.protocol.i8583.field.FieldComp;
import com.ifinc.common.utils.Log;
import com.ifinc.common.utils.encode.ByteUtil;
import org.slf4j.Logger;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * User: luotao
 * Date: 13-11-15
 * Time: 13:42
 */
public class I8583Request {

    private static Logger logger = Log.makeLogger(I8583Request.class);

    protected Map<Integer, Field> data = new LinkedHashMap<Integer, Field>();

    LinkedHashMap<Integer, Field> fieldInfo;

    protected List<Byte> dataByte = new LinkedList<Byte>();

    public static final int FIELD_LEN = 64;

    protected String zmk;

    protected String zak;

    protected boolean needMac = true;

    protected I8583Define i8583Define;

    protected I8583Request(I8583Define i8583Define) {
        this.i8583Define = i8583Define;
        fieldInfo = i8583Define.getFieldInfo();
        fillDataMap();
    }

    public void fillDataMap() {
        data = (Map<Integer, Field>) fieldInfo.clone();
        for (Map.Entry<Integer, Field> entry : data.entrySet()) {
            Field field = entry.getValue();
            field.setFieldId(entry.getKey());
            field.setProtocol(this);
        }
    }

    public void addFiled(Integer index, String str) {
        Field field = fieldInfo.get(index);
        if (field == null) {
            throw new RuntimeException("Field" + index + " undefined");
        }
        if (field.isAutoFill()) {
            throw new RuntimeException("this Field is AutoFill,not allow to add");
        }
        field.setSrcValue(str);
        data.put(index, field);
    }

    public void addSubField(Integer parentIndex,Integer subIndex,String str){
        Field field = fieldInfo.get(parentIndex);
        if(field==null){
            throw new RuntimeException("Field" + parentIndex + " undefined");
        }
        if(! (field instanceof FieldComp)){
            throw new RuntimeException("Field is not a instants of FieldComp,class name : "+field.getClass().getName());
        }
        FieldComp fieldComp = (FieldComp) field;
        fieldComp.addSubField(subIndex,str);
        data.put(parentIndex, fieldComp);
    }

    public byte[] encodeWithLen(){
        byte[] dataBytes = encode();
        int len = dataBytes.length;
        byte[] dataLenBytes = new byte[len+2];
        ByteUtil.writeShort(dataLenBytes,0,len);
        System.arraycopy(dataBytes,0,dataLenBytes,2,dataBytes.length);
        return dataLenBytes;
    }

    public byte[] encode() {
        for (Map.Entry<Integer, Field> entry : data.entrySet()) {
            Field field = entry.getValue();
            if (!field.isAutoFill() && field.getSrcBytes().length == 0) {
                continue;
            }
            byte[] fieldByte = field.toByte();
            logger.info(field.toString());
            dataByte.addAll(ByteUtil.byteArray2List(fieldByte));
        }
        return ByteUtil.list2ByteArray(dataByte);
    }

    public void decodeWithLen(byte[] bb){
        byte[] data = new byte[bb.length-2];
        System.arraycopy(bb,2,data,0,bb.length-2);
        int index =0;
        for (Map.Entry<Integer, Field> entry : fieldInfo.entrySet()) {
            Field field = entry.getValue();
            int readLen = field.toValue(data,index);
            index+=readLen;
        }
    }


    public Map<Integer, Field> getData() {
        return data;
    }

    public String getZmk() {
        return zmk;
    }

    public void setZmk(String zmk) {
        this.zmk = zmk;
    }

    public String getZak() {
        return zak;
    }

    public void setZak(String zak) {
        this.zak = zak;
    }



    public boolean isNeedMac() {
        return needMac;
    }

    public void setNeedMac(boolean needMac) {
        this.needMac = needMac;
    }

}
